package cn.com.smart.common.utils;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import java.util.UUID;

import javax.activation.DataSource;
import javax.activation.FileDataSource;
import javax.mail.BodyPart;
import javax.mail.Flags;
import javax.mail.Flags.Flag;
import javax.mail.Folder;
import javax.mail.Message;
import javax.mail.Message.RecipientType;
import javax.mail.MessagingException;
import javax.mail.Multipart;
import javax.mail.Part;
import javax.mail.Session;
import javax.mail.Store;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeUtility;

import org.apache.commons.mail.EmailAttachment;
import org.apache.commons.mail.EmailException;
import org.apache.commons.mail.HtmlEmail;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;

public final class MailUtils {
	
//	private static String logoPath;
	
//	static {
//		File logo = new File(System.getProperty("user.dir"), "logo.png");
//		if(!logo.exists()) {
//			final int MAX_SIZE = 4096;
//			int len;
//			byte[] buffer = new byte[MAX_SIZE];
//			try {
//				FileOutputStream out = new FileOutputStream(logo);
//				InputStream in = MailUtils.class.getClassLoader().getResourceAsStream("logo.jpg");
//				while((len = in.read(buffer, 0, MAX_SIZE)) != -1) {
//					out.write(buffer, 0, len);
//					out.flush();
//				}
//				out.close();
//				in.close();
//			} catch (IOException e) {
//				e.printStackTrace();
//			}
//		}
//		logoPath = logo.getAbsolutePath();
//		System.out.println("logoPath: " + logoPath);
//	}
	
	/**
	 * 
	 * @param subject 标题
	 * @param content 正文
	 * @param toAddress 收件人
	 * @param ccAddress 抄送人
	 * @param bccAddress 密送
	 * @param attachments 附件
	 */
	public static String sendEmail(MailConfig config, String subject, String body, List<String> toAddress, List<String> ccAddress,
			List<String> bccAddress, List<EmailAttachment> attachments, String sender, String tel, String mailAddress) throws EmailException {
		
//		System.out.println("******email config******");
//		System.out.println(config.getServerHost());
//		System.out.println(config.getPort());
//		System.out.println(config.getUserName());
//		System.out.println(config.getDisplayName());
//		System.out.println(config.isCheckserveridentity());
//		System.out.println(config.isStartTLSEnabled());
//		System.out.println(config.isSslOnConnect());
//		System.out.println(config.getCharSet());
//		System.out.println("******************");
		
		HtmlEmail email = new HtmlEmail();
		// 配置信息
		email.setHostName(config.getServerHost());
		email.setSmtpPort(config.getPort());
		email.setFrom(config.getUserName(), config.getDisplayName());
		email.setAuthentication(config.getUserName(), config.getPassword());
		email.setSSLCheckServerIdentity(config.isCheckserveridentity());
		email.setStartTLSEnabled(config.isStartTLSEnabled());
		if (config.isSslOnConnect()) {
			email.setSSLOnConnect(true);
			email.setSslSmtpPort(String.valueOf(config.getPort()));
		}
		email.setCharset(config.getCharSet());
		email.setSubject(subject);
//		DataSource ds = new FileDataSource(logoPath);
//        String cid = email.embed(ds, "logo.png");
		email.setHtmlMsg(htmlBody(body,sender, tel, mailAddress, null));

		// 添加附件
		if(attachments != null) {
			for (EmailAttachment attachment : attachments) {
				email.attach(attachment);
			}
		}

		// 收件人
		if(toAddress != null) {
			for (String to : toAddress) {
				email.addTo(to);
			}
		}

		// 抄送人
		if(ccAddress != null) {
			for (String cc : ccAddress) {
				email.addCc(cc);
			}
		}

		// 邮件模板 密送人
		if(bccAddress != null) {
			for (String bcc : bccAddress) {
				email.addBcc(bcc);
			}
		}

		return email.send();
	}
	
	private static String htmlBody(String body, String sender, String tel, String mailAddress, String cid) {
		StringBuilder sb = new StringBuilder("<html>")
				.append(body)
		        .append("<hr style=\"width: 210px; height: 1px;\" color=\"#b5c4df\" size=\"1\" align=\"left\">")
		        .append("<div>")
		        .append("<span>")
		        .append("<div style=\"MARGIN: 10px; FONT-FAMILY: verdana; FONT-SIZE: 10pt\">")
		        .append("<div style=\"font-family: 'Microsoft YaHei UI'; font-size: 14px; line-height: 21px; margin: 10px;\">")
		        .append("<b style=\"color: rgb(31, 73, 125); font-family: 宋体; font-size: small; line-height: 19.5px; orphans: 2; widows: 2;\">")
		        .append(sender)
		        .append("</b>")
		        .append("</div>")
		        .append("<div style=\"font-family: 'Microsoft YaHei UI'; font-size: 14px; line-height: 21px; margin: 10px;\">")
		        .append("<p class=\"MsoNormal\" style=\"margin: 0px 0cm; font-variant-ligatures: normal; orphans: 2; widows: 2;\">")
		        .append("<font color=\"#1f497d\" face=\"宋体\">")
		        .append("<span lang=\"EN-US\">")
		        .append("<span style=\"font-size: 13px;\">广东昱辉通信技术有限公司</span>")
		        .append("</span>")
		        .append("</font>")
		        .append("</p>")
		        .append("<p class=\"MsoNormal\" style=\"margin: 0px 0cm; font-variant-ligatures: normal; orphans: 2; widows: 2;\">")
		        .append("<span style=\"color: rgb(31, 73, 125); font-family: 宋体; font-size: 13px;\">手机</span>")
		        .append("<span lang=\"EN-US\" style=\"color: rgb(31, 73, 125); font-family: 宋体;\">")
		        .append("<span style=\"font-size: 13px;\">:")
		        .append(tel)
		        .append("</span>")
		        .append("</span>")
		        .append("</p>")
		        .append("<p class=\"MsoNormal\" style=\"margin: 0px 0cm; font-variant-ligatures: normal; orphans: 2; widows: 2;\">")
		        .append("<font color=\"#1f497d\" face=\"宋体\">")
		        .append("<span style=\"font-size: 13px;\">")
		        .append("邮件")
		        .append("<span style=\"line-height: 19.5px;\">:</span>")
//		        .append("<span style=\"line-height: 1.5;\">liuyue</span>")
		        .append("<span lang=\"EN-US\" style=\"line-height: 1.5;\">")
		        .append(mailAddress)
		        .append("</span>")
		        .append("</span>")
		        .append("</font>")
		        .append("</p>")
		        .append("<p class=\"MsoNormal\" style=\"margin: 0px 0cm; font-variant-ligatures: normal; orphans: 2; widows: 2;\">")
		        .append("<font color=\"#1f497d\" face=\"宋体\">")
		        .append("<span style=\"font-size: 13px;\">")
		        .append("<span lang=\"EN-US\">地址</span>")
		        .append("<span style=\"line-height: 19.5px;\">:</span>")
		        .append("<span lang=\"EN-US\">广州市天河区建中路64-66号佳都商务大厦西塔8楼</span>")
		        .append("</span>")
		        .append("</font>")
		        .append("</p>")
		        .append("<p class=\"MsoNormal\" style=\"margin: 0px 0cm; font-family: 宋体; font-variant-ligatures: normal; orphans: 2; widows: 2; color: rgb(51, 51, 51);\">")
		        .append("<span style=\"color: rgb(31, 73, 125);\">")
		        .append("<span lang=\"EN-US\" style=\"font-size: 13px;\">")
		        .append("<br>")
		        .append("</span>")
		        .append("</span>")
		        .append("</p>")
//		        .append("<p class=\"MsoNormal\" style=\"margin: 0px 0cm; font-family: 宋体; font-variant-ligatures: normal; orphans: 2; widows: 2; color: rgb(51, 51, 51);\">")
//		        .append("<img src=\"cid:")
//		        .append(cid)
//		        .append("\" border=\"0\" style=\"max-width: 100%; height: auto !important; font-family: verdana; color: rgb(0, 0, 0); font-size: 10.5pt; line-height: 1.5; background-color: transparent;\">")
//		        .append("<b style=\"color: rgb(31, 73, 125); font-size: small; line-height: 19.5px;\">人工智能及大数据解决方案提供商</b>")
//		        .append("</p>")
		        .append("<p class=\"MsoNormal\" style=\"margin: 0px 0cm; font-family: 宋体; font-size: 12pt; font-variant-ligatures: normal; orphans: 2; widows: 2; color: rgb(51, 51, 51);\">")
		        .append("<span style=\"color: rgb(31, 73, 125); font-size: 10.5pt;\">━━━━━━━━━━━━━━━━━━━━━━━━━</span>")
		        .append("</p>")
		        .append("</div>")
		        .append("</div>")
		        .append("</span>")
		        .append("</div>")
		        .append("</html>");
		return sb.toString();
	}
	
	public static List<JSONObject> recvEmail(int page, int size, MailConfig config) throws Exception {
		List<JSONObject> data = new ArrayList<JSONObject>(size);
		// 定义连接POP3服务器的属性信息
//        String pop3Server = "pop.126.com";
//        String protocol = "pop3";
//        String username = "dongchang_cai@126.com";
//        String password = "123456"; // QQ邮箱的SMTP的授权码，什么是授权码，它又是如何设置？
        
        Properties props = new Properties();
        if(config.isImap()) {
        	props.setProperty("mail.store.protocol", config.getProtocol()); // 使用的协议（JavaMail规范要求）
            props.setProperty("mail.imap.host", config.getServerHost()); // IMAP服务器地址
            props.setProperty("mail.imap.port", String.valueOf(config.getPort())); // IMAP服务端口
        } else {
        	props.setProperty("mail.transport.protocol", config.getProtocol()); // 使用的协议（JavaMail规范要求）
            props.setProperty("mail.smtp.host", config.getServerHost()); // 发件人的邮箱的 SMTP服务器地址
        }

        // 获取连接
        Session session = Session.getDefaultInstance(props);
        session.setDebug(false);

        // 获取Store对象
        Store store = session.getStore(config.getProtocol());
        store.connect(config.getServerHost(), config.getUserName(), config.getPassword()); // POP3服务器的登陆认证

        // 通过POP3协议获得Store对象调用这个方法时，邮件夹名称只能指定为"INBOX"
        Folder folder = store.getFolder("INBOX");// 获得用户的邮件帐户
//        folder.open(Folder.READ_WRITE); // 设置对邮件帐户的访问权限
        folder.open(Folder.READ_ONLY); // 设置对邮件帐户的访问权限
        
        System.out.println("size------" + folder.getMessageCount());
        int start = folder.getMessageCount() - (page + 1) * size;
        int end = start + size;
        Message[] messages;
        if(start >= 0 && end > 0 && folder.getMessageCount() >= end) {
        	messages = folder.getMessages(start + 1, end);
        } else if(end > 0 && folder.getMessageCount() >= end) {
        	messages = folder.getMessages(1, end);
        } else {
//        	messages = folder.getMessages(1, folder.getMessageCount());
        	messages = new Message[0];
        }
        for (Message message : messages) {
        	JSONObject mail = new JSONObject();
        	mail.put("subject", MimeUtility.decodeText(message.getSubject()));// 邮件标题
            InternetAddress from = (InternetAddress) message.getFrom()[0];// 获得发送者地址
            if(from.getPersonal() != null) {
            	mail.put("from_name", MimeUtility.decodeText(from.getPersonal()));
            }
            mail.put("from_address", MimeUtility.decodeText(from.getAddress()));
            mail.put("to", getRecipients(message, Message.RecipientType.TO));// 收件人
            mail.put("cc", getRecipients(message, Message.RecipientType.CC));// 抄送人
            mail.put("bcc", getRecipients(message, Message.RecipientType.BCC));// 密送
            mail.put("send_date", message.getSentDate().getTime());// 发送时间
            mail.put("need_reply", message.getHeader("Disposition-Notification-To") != null);
            for(Flag flag : message.getFlags().getSystemFlags()) {
            	if (flag == Flags.Flag.SEEN) {
            		mail.put("is_new", true);
            		break;
            	}
            }
            JSONArray attachment = new JSONArray();
            saveAttachMent(message, attachment, config.getFilePath());
            mail.put("attachment", attachment);// 附件
            JSONArray content = new JSONArray();
            getMailContent(message, content);
            mail.put("content", content);// 邮件正文
            data.add(mail);
        }

        folder.close(false);// 关闭邮件夹对象
        store.close();// 关闭连接对象
        return data;
	}
	
	private static JSONArray getRecipients(Message message, RecipientType type) throws MessagingException, UnsupportedEncodingException {
		InternetAddress[] address = null;
		if(type == Message.RecipientType.TO) {
			address = (InternetAddress[]) message.getRecipients(Message.RecipientType.TO);
		} else if(type == Message.RecipientType.CC) {
			address = (InternetAddress[]) message.getRecipients(Message.RecipientType.CC);
		} else if(type == Message.RecipientType.BCC) {
			address = (InternetAddress[]) message.getRecipients(Message.RecipientType.BCC);
		}
		JSONArray array = new JSONArray();
		if(address != null) {
			for(InternetAddress addr : address) {
				JSONObject json = new JSONObject(2);
				if(addr.getPersonal() != null) {
					json.put("name", MimeUtility.decodeText(addr.getPersonal()));
				}
				json.put("address", MimeUtility.decodeText(addr.getAddress()));
				array.add(json);
			}
		}
		return array;
	}
	
	private static void getMailContent(Part part, JSONArray content) throws Exception {
        String contentType = part.getContentType();
        if (part.isMimeType("text/plain")) {
            // text/plain 类型
        	JSONObject json = new JSONObject(2);
        	json.put("contentType", contentType);
        	if(contentType.toLowerCase().contains("gb2312")) {
        		StringBuilder body = new StringBuilder();
        		BufferedReader br = new BufferedReader(new InputStreamReader(part.getInputStream(), "GB18030"));
        		String line;
        		while((line = br.readLine()) != null) {
        			body.append(line)
        			.append("\n");
        		}
        		br.close();
        		json.put("content", body.toString());
        	} else {
        		json.put("content", part.getContent());
        	}
        	content.add(json);
        } else if (part.isMimeType("text/html")) {
            // text/html 类型
        	JSONObject json = new JSONObject(2);
        	json.put("contentType", contentType);
        	if(contentType.toLowerCase().contains("gb2312")) {
        		StringBuilder body = new StringBuilder();
        		BufferedReader br = new BufferedReader(new InputStreamReader(part.getInputStream(), "GB18030"));
        		String line;
        		while((line = br.readLine()) != null) {
        			body.append(line)
        			.append("\n");
        		}
        		br.close();
        		json.put("content", body.toString());
        	} else {
        		json.put("content", part.getContent());
        	}
        	content.add(json);
        } else if (part.isMimeType("multipart/*")) {
            // multipart/*
            Multipart multipart = (Multipart) part.getContent();
            int counts = multipart.getCount();
            for (int i = 0; i < counts; i++) {
                getMailContent(multipart.getBodyPart(i), content);
            }
        } else if (part.isMimeType("message/rfc822")) {
            // message/rfc822
            getMailContent((Part) part.getContent(), content);
        }
    }
	
	private static void saveAttachMent(Part part, JSONArray attachment, String filePath) throws Exception {
        String fileName = "";
        if (part.isMimeType("multipart/*")) {
            Multipart mp = (Multipart) part.getContent();
            for (int i = 0; i < mp.getCount(); i++) {
                BodyPart mPart = mp.getBodyPart(i);
                String disposition = mPart.getDisposition();
                if ((disposition != null)
                        && ((disposition.equals(Part.ATTACHMENT)) || (disposition
                                .equals(Part.INLINE)))) {
                    fileName = mPart.getFileName();
                    if (fileName.toLowerCase().indexOf("gb2312") != -1) {
                        fileName = MimeUtility.decodeText(fileName);
                    }
                    JSONObject file = new JSONObject(2);
                    file.put("id", UUID.randomUUID().toString());
                    file.put("name", fileName);
                    attachment.add(file);
                    saveFile(file.getString("id"), mPart.getInputStream(), filePath);
                } else if (mPart.isMimeType("multipart/*")) {
                    saveAttachMent(mPart, attachment, filePath);
                } else {
                    fileName = mPart.getFileName();
                    if ((fileName != null)
                            && (fileName.toLowerCase().indexOf("GB2312") != -1)) {
                        fileName = MimeUtility.decodeText(fileName);
                        JSONObject file = new JSONObject(2);
                        file.put("id", UUID.randomUUID().toString());
                        file.put("name", fileName);
                        attachment.add(file);
                        saveFile(file.getString("id"), mPart.getInputStream(), filePath);
                    }
                }
            }
        } else if (part.isMimeType("message/rfc822")) {
            saveAttachMent((Part) part.getContent(), attachment, filePath);
        }
    }
	
	private static void saveFile(String fileName, InputStream in, String filePath) throws Exception {
        File path = new File(filePath);
        if(!path.exists()) {
        	path.mkdirs();
        }
        File storeFile = new File(path, fileName);
        BufferedInputStream bis = null;
        BufferedOutputStream bos = null;
        final int MAX_SIZE = 4096;
        int len;
        byte[] buffer = new byte[MAX_SIZE];
        try {
            bos = new BufferedOutputStream(new FileOutputStream(storeFile));
            bis = new BufferedInputStream(in);
            while ((len = bis.read(buffer, 0, MAX_SIZE)) != -1) {
                bos.write(buffer, 0, len);
                bos.flush();
            }
        } catch (Exception e) {
            e.printStackTrace();
            throw e;
        } finally {
        	if(bos != null) {
        		try {
        			bos.close();
        		} catch(IOException e) {
        			e.printStackTrace();
        		}
        	}
        	if(bis != null) {
        		try {
        			bis.close();
        		} catch(IOException e) {
        			e.printStackTrace();
        		}
        	}
        }
    }

}
